<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <div id="app">
    <div></div>
    <!-- <input type="text" value='123' @input='handle' /> -->

    <!-- xxx是自定义属性，有:表示“动态属性” -->
    <!-- yyy是自定义属性，没有:表示“静态属性” -->
    <!-- zzz是自定义事件 -->
    <!-- default自定义插槽 -->
    <qf-button :xxx='xxx' :yyy='true' @zzz='xxx=$event'>
      <div>测试插槽233232</div>
    </qf-button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <script>

    // 理解组件
    // 本质：就是html的扩展。结论我们在使用组件时，你要把它成html元素一样的感觉来使用。
    // 约定：我们通常把那些除了HTML标签以外的自定义组件，才称之“组件”。结论是，我们说“父组件”“子组件”指是自定义组件之间的关系。

    // 组件化的意义
    // 1、封装（复用、把逻辑隐藏起来、提高可维护性）
    // 2、快速开发（搭积木）

    // 如何定义一个组件？
    // 语法：Vue.component('组件名', '选项')
    // 第一个参数，“组件名”：组件名必须是两个以上的“单词”、并且要用中划线连接。
    // 第二个参数，“选项”：除了el不能用，其它选项都可以使用，比如data、methods、生命周期、computed、watch等。
    // template选项：对组件来讲，有一个必须的选项是template，这个选项用于指定当前组件的视图模板（HTML字符串），在视图模板中可以使用我们学过的所有指令。
      // template视图结构必须是“单一根节点”
    // data选项：组件可以有自己独立的data选项，但是data不再是一个{}，必须是一个工厂函数。

    // props选项：props专门用于接受从父组件作用域向子组件传递“自定义属性”，props接收之后可以通过this访问。所以props数据在当前组件中可以用在指令中、其它选项中。
      // 父组件向子组件传递数据，子组件使用props接收，可以传递基本数据类型、引用数据类型。

    // $emit('自定义事件名称', ...“将要回传给父组件的数据列表”)：用于触发一个自定义事件，向父组件传递数据。

    // 结论：组件化的核心是 “自定义属性props” “自定义事件$emit()” “自定义插槽<slot>”
      // 1、props，是子组件的一个选项，用于接收父组件给我的自定义属性 => v-bind 简写 :
      // 2、$emit()，是一个vue api，用于触发父组件给我的自定义事件（向父组件发数据）=> v-on 简写 @
      // 3、<slot>，是vue的一个内置组件，可以直接用，我称它为“插槽” => v-slot 简写 #

    Vue.component('qf-abc', {
      template: `<a href="#">百度</a>`,
      mounted(){console.log('qf-abc', this)}
    })

    // qf-button所需要的原材料
    const btnOpt = {
      template: `
      <div>
        <span v-text='xxx'></span>
        <button @click='send'>向父组件传递数据</button>
        <slot></slot>
      </div>
      `,
      data() {
        // do something
        // return 必须返回一个对象，这个对象就是我们的声明式变量
        return {
          msg: 'hello button'
        }
      },
      props: {
        xxx: { type: Number, required: false, default: '' },
        yyy: { type: Boolean, required: false, default: false }
      },
      mounted() { console.log('qf-button', this)},
      methods: {
        send() {
          // this.$emit('zzz', {target:{value:Math.random()}})
          this.$emit('zzz', Math.random())
        }
      }
    }

    // 定义组件（全局注册组件）
    // Vue.component('qf-button', btnOpt)

    // 创建一个根组件
    const app = new Vue({
      // 只有根组件才能使用el
      el: '#app',
      mounted() { console.log('app', this) },
      // 定义组件（局部注册组件）
      components: {
        'qf-button': btnOpt
      },
      data: {
        xxx: 111
      }
    })
  </script>

  <script>
    // 工厂函数
    function factory() {
      return {
        a: 1,
        b: 2
      }
    }
    const app1 = factory()
    const app2 = factory()
  </script>
</body>
</html>
